function SpCombobox(clientName, divMenuId, textId, valueId, panelId, filterType, selectText, selectKey, itemIndex, milisecondForTimeout, dataMenuIdForFilterMode, displayEffect, timeEffect, stepEffect, enable, dontShowIfEmplty, showKey) {
  var _hashParameter = Library.WebControl.Hashtable.CreateHashtable();
  var _instance = this;
  var _util = Library.WebControl.Util;
  var _divMenuId = divMenuId;
  var _textId = textId;
  var _valueId = valueId;
  var _panelId = panelId;
  var _filterType = filterType;
  var _isFirstShow = true;
  var _selectItemIndex = itemIndex;
  var _selectKey = selectKey;
  var _selectText = selectText;
  var _timerObject = 0;
  var _miliseconForTimeout = milisecondForTimeout;
  var _dataMenuIdForFilerMode = dataMenuIdForFilterMode;
  var _effectControl = null;
  var _displayEffect = displayEffect;
  var _timeEffect = timeEffect;
  var _stepEffect = stepEffect;
  var _currentScrollTop = 0;
  var _currentScrollLeft = 0;
  var _noItemMatchText = "No item match";
  var _enable = enable;
  var _allowRaiseSelectIndexChangedEvent = true;
  var _firstCallDivMenuData = true;
  var _dontShowIfEmpty = dontShowIfEmplty;
  var _selectIndexChanged = null;
  var _shown = null;
  var _showing = null;
  var _grid = null;
  var _gridColumnIndex = -1;
  var _textChanged = null;
  var _showKey = showKey;
  _globalHashObject.Add(clientName, _instance);
  window[clientName] = _instance;

  this.NoItemMatchText = function() {
    if (arguments.length > 0)
      _noItemMatchText = arguments[0];
    return _noItemMatchText;
  };
  function getDivMenu() {
    return _util.GetObjectById(_divMenuId);
  };
  function getTextControl() {
    return _util.GetObjectById(_textId);
  };
  function getValueControl() {
    return _util.GetObjectById(_valueId);
  };
  this.Enable = function() {
    if (arguments.length > 0) {
      _enable = arguments[0];
      var clzz = enable ? "excbInputPanel" : "excbInputPanelDisable";
      _util.SetClass(_util.GetObjectById(_panelId), clzz);
    }
    return _enable;
  };

  this.Visible = function() {
    var panel = _util.GetObjectById(_panelId);
    if (arguments.length > 0) {
      if (arguments[0]) {
        panel.style.display = "";
      } else {
        panel.style.display = "none";
      }
    }
    return panel.style.display != "none";
  };

  function initDivMenuDataIfTheFirstCall() {
    if (_firstCallDivMenuData && _filterType == 1) {
      _firstCallDivMenuData = false;
      clientFilterWithoutShow("");
    }
  };
  function showOrHide() {
    if (!_enable)
      return;
    if (isMenuVisible()) {
      _instance.Hide();
    }
    else {
      _instance.Show();
      // cancel out any text selections

    }
  };
  this.Show = function() {
    var ev = { Cancel: false };
    if (_showing != null) _showing(_instance, ev);
    if (ev.Cancel) return;
    if (!_enable)
      return;
    if (isMenuVisible()) {
      return;
    }
    initDivMenuDataIfTheFirstCall();
    var divMenu = getDivMenu();
    if (divMenu.childNodes.length == 0 && _dontShowIfEmpty)
      return;
    divMenu.style.zIndex = _util.GetMaxZindex() + 1;
    divMenu.style.display = "block";
    if (_effectControl == null) {
      _effectControl = Library.WebControl.Effect.Create({
        Object: divMenu,
        Type: _displayEffect,
        Time: _timeEffect,
        Step: _stepEffect,
        ObjHeight: divMenu.clientHeight,
        ObjWidth: divMenu.clientWidth,
        Vision: 'V',
        ShowComplete: function(s, e) {
          divMenu.style.display = "block";
          divMenu.style.overflow = "auto";
          divMenu.scrollTop = _currentScrollTop;
          divMenu.scrollLeft = _currentScrollLeft;
          var divSize = _util.GetSize(divMenu);
          var panelSize = _util.GetSize(_panelId);
          if (divSize.W < panelSize.W) {
            divMenu.style.width = panelSize.W + "px";
          }
          if (_grid != null) setTimeout(function() { _grid.SetFocus() }, 100);
          if (_shown != null)
            _shown(_instance, {});
        },
        HideComplete: function(s, e) {
          divMenu.style.display = "none";
          //divMenu.style.top = "-1000px";
          //divMenu.style.left = "-1000px";
          divMenu.style.zIndex = 0;
        }
      });
    }
    _effectControl.Show();

    document.onmousedown = function(e) {
      if (divMenu.style.visibility != "hidden") {
        var mos = _util.GetMousePosition(e);
        var pn = _util.GetObjectById(_panelId);
        var ppos = _util.GetPosition(pn);
        var pSize = {
          W: pn.offsetWidth,
          H: pn.offsetHeight
        };
        if (mos.X >= ppos.X && mos.X <= ppos.X + pSize.W && mos.Y >= ppos.Y && mos.Y <= ppos.Y + pSize.H)
        // click on input panel, do nothing let input panel process this event
          return;
        var dpos = _util.GetPosition(divMenu);
        var dSziw = {
          W: pSize.W > divMenu.offsetWidth ? pSize.W : divMenu.offsetWidth,
          H: divMenu.offsetHeight
        };
        if (mos.X < dpos.X || mos.X > dpos.X + dSziw.W || mos.Y < dpos.Y || mos.Y > dpos.Y + dSziw.H) {
          _instance.Hide();
        }
      }

    };
    if (_isFirstShow) {
      _isFirstShow = false;
      _allowRaiseSelectIndexChangedEvent = false;
      if (_selectItemIndex >= 0) {
        var oldSelectItemIndex = _selectItemIndex;
        _selectItemIndex = -1;
        silentMoveToItemIndex(oldSelectItemIndex);
      }
      _allowRaiseSelectIndexChangedEvent = true;
    }
  };
  this.GetText = function() {
    return getTextControl().value;
  };
  this.SetText = function(text) {
    getTextControl().value = text;
  };
  this.GetValue = function() {
    return getValueControl().value;
  };
  this.SetValue = function(v) {
    if (v == null) v = "";
    if (v == _instance.GetValue())
      return;
    _allowRaiseSelectIndexChangedEvent = false;
    if (v == "") {
      silentMoveToItemIndex(-1);
    }
    else {
      _isFirstShow = true;
      initDivMenuDataIfTheFirstCall();
      var dm = getDivMenu();
      for (var i = 0; i < dm.childNodes.length; i++) {
        var c = dm.childNodes[i];
        var k = getValueFromMenuItem(c);
        if (k == v) {
          silentMoveToItemIndex(i);
          _allowRaiseSelectIndexChangedEvent = true;
          return;
        }
      }
      // no value match, set text at the same value
      getValueControl().value = v;
      _instance.SetText(v);
    }
    _allowRaiseSelectIndexChangedEvent = true;
  };
  this.Hide = function() {
    var divMenu = getDivMenu();
    _currentScrollTop = divMenu.scrollTop;
    _currentScrollLeft = divMenu.scrollLeft;
    if (_effectControl) {
      _effectControl.Hide();
    }
    document.onmousedown = null;
  };

  function keyDown(e) {
    if (!_enable) {
      //          var ev = _util.GetEvent(e);
      //                    ev.cancelBubble = true;
      //                    if (ev.returnValue) 
      //                        ev.returnValue = false;
      return true;
    }
    if (_showKey > 0)
      if (!_util.HandlePress(e, _showKey, function() { _instance.Show(); })) {
      return false;
    }
    if (_grid != null) {
      //if (k == 13) {// enter
      //var row = _grid.GetSelectedRow();
      //if (row != null)
      //	_instance.Call(7, row);
      //}
      return true;
    }
    var k = _util.GetKey(e);
    switch (k) {
      case _util.Keys.ARROW_UP: //Up arrow	
        moveToItemIndex(_selectItemIndex - 1);
        break;
      case _util.Keys.ARROW_DOWN: //Down arrow	
        //this.MoveDown();
        moveToItemIndex(_selectItemIndex + 1);
        break;
      case _util.Keys.TAB: //tab
      case _util.Keys.ENTER: //Enter	
        if (isMenuVisible()) {
          _instance.Hide();
          var ev = _util.GetEvent(e);
          ev.cancelBubble = true;
          if (ev.returnValue)
            ev.returnValue = false;
        } else {
          return true;
        }
        break;
      default: // let parent process this key
        return true;
    }
    return false;
  };
  function keyUp(e) {
    if (!_enable)
      return false;
    var k = _util.GetKey(e);
    if (k == _util.Keys.ENTER) {
      if (_grid != null) {
        var row = _grid.GetSelectedRow();
        if (row != null) {
          _instance.Call(7, row);
          return false;
        }
      }
      return true;
    }
    if (_filterType == 0)
      return;
    switch (k) {
      case _util.Keys.ARROW_UP: //Up arrow
      case _util.Keys.ARROW_DOWN: //Down arrow			
        return true;
      default:
        if (_grid != null) return true;
        if (_instance.GetText() == _selectText)
          return true;
        if (_timerObject) {
          window.clearTimeout(_timerObject);
        }

        if (_filterType == 1) {//client filter
          _timerObject = window.setTimeout(function() {
            clientFilter(_instance.GetText().toLowerCase());
          }, _miliseconForTimeout);
        }
        else
          if (_filterType == 2) {
          _timerObject = window.setTimeout(function() {
            serverFilter(_instance.GetText());
          }, _miliseconForTimeout);
        }
        return true; ;
    }
  };


  function clientFilterWithoutShow(tx) {
    _selectItemIndex = -1;
    getValueControl().value = "";
    var nodes = new Array();
    var dataMenu = _util.GetObjectById(_dataMenuIdForFilerMode);
    var cs = dataMenu.childNodes;
    for (var i = 0; i < cs.length; i++) {
      if (cs[i].tagName.toLowerCase() == "div") {
        var t = getTextFromMenuItem(cs[i]).toLowerCase();
        if (t.indexOf(tx) == 0 || tx == "") {
          nodes.push(cs[i].cloneNode(true));
        }
      }
    }
    var dm = getDivMenu();
    while (dm.firstChild) {
      dm.removeChild(dm.firstChild);
    }

    for (var j = 0; j < nodes.length; j++) {
      var node = nodes[j];
      if (getTextFromMenuItem(node) == tx) {
        _selectItemIndex = j;
        getValueControl().value = getValueFromMenuItem(node);
        _util.SetClass(node, "spexcbMenuItemActive");
      }
      node.onclick = function() {
        selecteItem(this);
      };
      dm.appendChild(node);
    }
    if (nodes.length == 0) {
      var noItemDiv = document.createElement("div");
      _util.SetClass(noItemDiv, "excbNoItem");
      noItemDiv.innerHTML = _noItemMatchText;
      dm.appendChild(noItemDiv);
    }

  };


  function clientFilter(tx) {
    clientFilterWithoutShow(tx);
    if (!isMenuVisible())
      _instance.Show();
  };
  function selecteItem(item) {
    var divMenu = getDivMenu();
    var childItemList = divMenu.childNodes;
    for (var i = 0; i < childItemList.length; i++) {
      if (item == childItemList[i]) {
        selectItemIndex(i);
        return;
      }
    }
  };
  function serverFilter(tx) {
    commonSendCallback("F", tx, function(s, e) { });
    if (!isMenuVisible()) {
      _instance.Show();
    }
  };
  function commonSendCallback(callbackType, parameter, callbackFunction) {
    var ajaxRequest = Library.WebControl.Ajax.CreateRequest();
    ajaxRequest.SetData("__SPEXCOMBOBOXRQP_=T&__SPEXCOMBOBOXRQF_=" + callbackType + "&__SPEXCOMBOBOXRQSID_=" + _divMenuId + "&__SPEXCOMBOBOXRQD_=" + encodeURIComponent(parameter) + "&" + _hashParameter.ToQuery());
    _hashParameter.Clear();
    ajaxRequest.SendCallback({
      P: parameter,

      F: callbackFunction
    }, callbackComplete);
  };
  this.GetInnerGrid = function() {
    return _grid;
  };
  this.SendCallback = function(parameter, callbackFunction) {
    if (_grid != null) _grid.SendCallback(parameter, callbackFunction);
    else commonSendCallback("C", parameter, callbackFunction);
  };
  function callbackComplete(sender, args) {
    var callbackEventArgs = _util.ParseAjaxResponse(args.ResponseText);
    callbackEventArgs.Parameter = sender.P;
    var responseResult = callbackEventArgs;
    if (!callbackEventArgs.IsValid) {
      alert(responseResult.Result);
    }
    else {
      var divMenu = getDivMenu();
      if (_filterType == 1) {//filter from client, so data item response from callback must be belong to datamenuforfilter client mode
        divMenu = _dataMenuIdForFilerMode;
        _firstCallDivMenuData = true;
      }
      _util.EvalScriptAndHtml(responseResult.Data, divMenu);
      _selectItemIndex = -1;
    }
    if (sender.F && typeof (sender.F) == "function") {
      sender.F(_instance, callbackEventArgs);
    }
  };

  function keyPress(e) {
    if (!_enable)
      return false;
    //var key = _util.GetKey(e);
    //if (key == 115) {// F4     
    //		_instance.Show();
    //		return false;       
    //	}
    //if (!_util.HandlePress(e, 115, function(){_instance.Show();})) return false;
    if (_grid != null) return true;
    return _util.HandleEnPress(e, function() { });
  };

  function selectItemIndex(itemIndex) {
    silentMoveToItemIndex(itemIndex);
    _instance.Hide();
  };

  function moveToItemIndex(itemIndex) {
    if (!isMenuVisible()) {
      _instance.Show();
    }
    silentMoveToItemIndex(itemIndex);
  };
  function raiseSelectIndexChangeEvent() {
    if (_allowRaiseSelectIndexChangedEvent && _selectIndexChanged != null)
      _selectIndexChanged(_instance, {});
  };
  function silentMoveToItemIndex(itemIndex) {
    initDivMenuDataIfTheFirstCall();
    var divMenu = getDivMenu();
    var childItemList = divMenu.childNodes;
    if (itemIndex < 0) {
      if (_selectItemIndex != -1) {
        _util.SetClass(childItemList[_selectItemIndex], "spexcbMenuItem");
        raiseSelectIndexChangeEvent();
      }
      _selectItemIndex = -1;
      getValueControl().value = "";
      divMenu.scrollTop = 0;
      getTextControl().value = "";
      _selectText = "";

    }
    else {
      if (itemIndex >= childItemList.length) {
        return;
      }
      else {
        var mi = childItemList[itemIndex];
        var menuValue = getValueFromMenuItem(mi);
        if (menuValue == null)
          return;
        if (_selectItemIndex >= 0 && _selectItemIndex < childItemList.length) {
          _util.SetClass(childItemList[_selectItemIndex], "spexcbMenuItem");
        }
        _selectItemIndex = itemIndex;


        _util.SetClass(mi, "spexcbMenuItemActive");
        getValueControl().value = menuValue;
        var text = getTextFromMenuItem(mi);
        getTextControl().value = text;
        _selectText = text;

        var dmPos = _util.GetPosition(divMenu);
        var dmSize = _util.GetSize(divMenu);
        var viPos = [dmPos.Y + divMenu.scrollTop, dmPos.Y + divMenu.scrollTop + dmSize.H];
        var mPos = _util.GetPosition(mi);
        if (viPos[0] > mPos.Y) {
          divMenu.scrollTop -= viPos[0] - mPos.Y;
        }
        else {
          var mSize = _util.GetSize(mi);
          if (viPos[1] < mPos.Y + mSize.H) {
            divMenu.scrollTop += mPos.Y + mSize.H - viPos[1];
          }
        }
        raiseSelectIndexChangeEvent();
      }
    }
  };
  function getTextFromMenuItem(mi) {
    return mi.getAttribute("_spexcomboboxtext_");
  };
  function getValueFromMenuItem(mi) {
    return mi.getAttribute("_spexcomboboxkey_");
  };
  function isMenuVisible() {
    return getDivMenu().style.visibility != "hidden";
  };
  this.AddHandler = function(t, f) {
    switch (t) {
      case 1: // select index changed
        _selectIndexChanged = f;
        break;
      case 2: // Shown
        _shown = f;
        break;
      case 3: // Showing
        _showing = f;
        break;
      case 4: // before callback
        if (_grid != null) {
          _grid.AddHandler(1, f);
        }
        break;
      case 5: // text changed
        _textChanged = f;
        break;

    }
  };

  this.AddParameter = function(a, b) {
    if (_grid != null) _grid.AddParameter(a, b);
    else _hashParameter.Add(a, b);
  };
  this.InitEx = function(g, c) {
    _grid = g;
    _gridColumnIndex = c;
  };
  this.Call = function(t, p) {
    switch (t) {
      case 1: // text change
        textChange();
        break;
      case 2: // showorhide
        showOrHide();
        break;
      case 3: // keyup
        return keyUp(p);
        break;
      case 4: //keydown
        return keyDown(p);
        break;
      case 5: // keyPress
        return keyPress(p);
      case 6: // select index
        selectItemIndex(p);
        break;
      case 7: // grid select row
        if (_grid != null) {
          var key = _grid.GetKeyFromRow(p);
          var text = "";
          if (_gridColumnIndex > -1) {
            text = _util.Trim(p.cells[_gridColumnIndex].innerHTML);
          } else {
            text = p.getAttribute("_excbxtext_");
          }
          var oldKey = _instance.GetValue();
          var oldText = _instance.GetText();
          _instance.SetText(text);
          if (oldText != text) if (_textChanged != null) _textChanged(_instance, {});
          _instance.SetValue(key);
          _instance.Hide();
          _grid.Call(5, p);
          if (oldKey != key) {
            if (_selectIndexChanged != null) _selectIndexChanged(_instance, {});
          }
        }

        break;
    }
  };



  function textChange() {
    if (_textChanged != null) _textChanged(_instance, {});
    var v = getTextControl().value;
    initDivMenuDataIfTheFirstCall();
    var dm = getDivMenu();
    for (var i = 0; i < dm.childNodes.length; i++) {
      var c = dm.childNodes[i];
      var k = getTextFromMenuItem(c);
      if (k == v) {
        getValueControl().value = getValueFromMenuItem(c);
        silentMoveToItemIndex(i);
        return;
      }
    }
    silentMoveToItemIndex(-1);
    getTextControl().value = v;

  };
};